/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：
* CreateTime：2020-05-14 14:13:43
* Version：1.0
* Modify Recorder：
*************************************************/

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;

//摄像机参数
[System.Serializable]
public class CamPara
{
    [Header("Orbit")]
    public bool allowHorizontalRotate = true;
    public bool limitYAngle = false;
    public float minYAngle;
    public float maxYAngle;

    [Space(5)]
    public bool allowVerticalRotate = true;
    public bool limitXAngle = true;
    public float minXAngle = -10;
    public float maxXAngle = 80;

    [Space(5)]
    public float mouseMoveRatio = 1;
    public float orbitSmooth = 1;

    [Header("Zoom")]
    public float minDistance = 2;
    public float maxDistance = 8;
    
    [Space(5)]
    public float mouseScrollRatio = 1;
    public float zoomSmooth = 1;
}

public class CameraOrbit : MonoBehaviour
{
    public Transform camRotationTf;
    public Transform camZoomTf;
    [Range(0,2)]
    public int button;
    public bool ignoreUIThrough = true;

    [Space(5)]
    public CamPara camOrbitPara;

    private Vector3 lastMousePos;
    [SerializeField]
    private Vector3 targetEulerAngle;
    [SerializeField]
    private Vector3 eulerAngle;

    private float lastTouchDistance;
    private float camDistance;
    private float targetCamDistance;
  
    private Quaternion originalRotation;

    private void Start()
    {
        originalRotation = camRotationTf.rotation;
        camDistance = camZoomTf.localPosition.z;
        targetCamDistance = camDistance;
        
        eulerAngle = camRotationTf.localEulerAngles;
        targetEulerAngle = eulerAngle;
    }

    private void LateUpdate() 
    {
        Orbit();
        Zoom();
    }

    //实现摄像机旋转功能
    private void Orbit()
    {
        if(ignoreUIThrough && EventSystem.current != null 
           && EventSystem.current.IsPointerOverGameObject()) return;

        if (Input.GetMouseButtonDown(button))
        {
            lastMousePos = Input.mousePosition;
        }

        if (Input.GetMouseButton(button))
        {
            if (camOrbitPara.allowVerticalRotate)
                targetEulerAngle.x += -(Input.mousePosition.y - lastMousePos.y) * camOrbitPara.mouseMoveRatio * 0.3f;
            if (camOrbitPara.allowHorizontalRotate)
                targetEulerAngle.y += (Input.mousePosition.x - lastMousePos.x) * camOrbitPara.mouseMoveRatio * 0.3f;

            if (camOrbitPara.limitXAngle)
                targetEulerAngle.x = Mathf.Clamp(targetEulerAngle.x, camOrbitPara.minXAngle, camOrbitPara.maxXAngle);

            if (camOrbitPara.limitYAngle)
                targetEulerAngle.y = Mathf.Clamp(targetEulerAngle.y, camOrbitPara.minYAngle, camOrbitPara.maxYAngle);

            lastMousePos = Input.mousePosition;

            //单指滑动
            if (Input.touchCount < 2)
            {
                eulerAngle = Vector3.Lerp(eulerAngle, targetEulerAngle, Time.deltaTime * camOrbitPara.orbitSmooth * 2);
                camRotationTf.rotation = originalRotation * Quaternion.Euler(eulerAngle);
            }
        }

        if (Input.GetMouseButtonUp(button))
        {
            StopCoroutine("EndRotateSmooth"); 
            if (Vector3.Distance(eulerAngle, targetEulerAngle) > 0.5f)
                StartCoroutine("EndRotateSmooth");
        }
    }

    //停止滑动的时候，缓动停止旋转
    IEnumerator EndRotateSmooth()
    {
        while (Vector3.Distance(eulerAngle, targetEulerAngle) > 0.5f)
        {
            eulerAngle = Vector3.Lerp(eulerAngle, targetEulerAngle, Time.fixedDeltaTime * camOrbitPara.orbitSmooth * 3);
            camRotationTf.rotation = originalRotation * Quaternion.Euler(eulerAngle);

            yield return null;
        }
    }

    //实现视角缩放功能
    private void Zoom()
    {
        if (Input.touchCount < 2)   
        {
            float value = Input.GetAxis("Mouse ScrollWheel");
            if (Math.Abs(value) > 0.01f)    
            {
                camDistance = -camZoomTf.localPosition.z;
                targetCamDistance = camDistance - value * camOrbitPara.mouseScrollRatio * 10;
                targetCamDistance = Mathf.Clamp(targetCamDistance, camOrbitPara.minDistance, camOrbitPara.maxDistance);
            }
        }
        else
        {
            float dis = Vector2.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
            if (Input.GetTouch(1).phase == TouchPhase.Began)
                lastTouchDistance = dis;

            if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
            {
                camDistance = -camZoomTf.localPosition.z;
                targetCamDistance = camDistance - (dis - lastTouchDistance) * camOrbitPara.mouseScrollRatio;

                lastMousePos = Input.mousePosition;
            }
        }
        if (Mathf.Abs(targetCamDistance - camDistance) > 0.1f)
        {
            camDistance = Mathf.Lerp(camDistance, targetCamDistance, Time.deltaTime * camOrbitPara.zoomSmooth * 3);
            camZoomTf.localPosition = new Vector3(camZoomTf.localPosition.x, camZoomTf.localPosition.y, -camDistance);
        }
    }
}
